<?php

declare( strict_types = 1 );

namespace App\Common\Model\Base\DataUnit;

use App\Common as com;
use App\Common\Model\Base\DataUnit\DataOperate as nameDataOperate;
use App\Common\Model as nameModel;
use App\Common\Model\Base as nameBase;
use Hyperf\DbConnection\Db;
use App\Common\Model\Base\DataUnit as nameDataUnit;

class DataOperate extends nameDataUnit\Base {

	/**
	 * @var string
	 */
	private string $_dataFieldName;


	/**
	 * 字段名（下划线）
	 * @var string|null
	 */
	private ?string $_dataFieldNameAsUnderline = null;

	/**
	 * DirectData constructor.
	 * @param nameBase\DataUnit $dataUnit
	 * @param string $dataFieldName
	 * @throws
	 */
	public function __construct( nameBase\DataUnit $dataUnit, string $dataFieldName ) {
		$this->_dataFieldName = $dataFieldName;
		//
		parent::__construct( $dataUnit );
	}

	/**
	 * 获取字段名(驼峰命名)
	 * @return string
	 */
	public function getName():string {
		return $this->_dataFieldName;
		// return com\Lib\Fun\Str::parseName( $this->_dataFieldName );
	}

	/**
	 * 获取字段名(下划线命名)
	 * @return string
	 */
	public function getNameAsSql():string {
		if( $this->_dataFieldNameAsUnderline === null ){
			$this->_dataFieldNameAsUnderline = com\Lib\Fun\Str::parseNameAsUnderline( $this->getName() );
		}
		//
		return $this->_dataFieldNameAsUnderline;
	}

	/**
	 * 获取字段名(下划线命名)，包含表名
	 * @return string
	 */
	public function getFullNameAsSql():string {
		return $this->getDataUnit()->getTableName() . '.' . $this->getNameAsSql();
	}

	/**
	 * sum
	 * @return mixed
	 */
	public function sum() {
		return $this->getDataUnit()->goDataset()->sum( $this->getName() );
	}

	/**
	 * min
	 * @return mixed
	 */
	public function min() {
		return $this->getDataUnit()->goDataset()->min( $this->getName() );
	}

	/**
	 * max
	 * @return mixed
	 */
	public function max() {
		return $this->getDataUnit()->goDataset()->max( $this->getName() );
	}

	/**
	 * 自增
	 * @param float|int $num 递增值
	 * @return $this
	 */
	public function incrementAsSet( float|int $num = 1 ):self {
		$this->getDataUnit()->goDataset()->set( $this->getName(), Db::raw( "`" . $this->getNameAsSql() . "`+{$num}" ) );
		//
		return $this;
	}

	/**
	 * 自减
	 * @param float|int $num 递增值
	 * @return $this
	 */
	public function decrementAsSet( float|int $num = 1 ):self {
		$this->getDataUnit()->goDataset()->set( $this->getName(), Db::raw( "`" . $this->getNameAsSql() . "`-{$num}" ) );
		//
		return $this;
	}

	/**
	 * 自增(马上执行)
	 * @param float|int $num 递增值
	 * @param array $extra 指定要更新的字段，如：['name' => 'John']
	 * @return int 变化的行数
	 */
	public function increment( float|int $num = 1, array $extra = [] ):int {
		return $this->getDataUnit()->goDataset()->increment( $this->getName(), $num, $extra );
	}

	/**
	 * 自减(马上执行)
	 * @param float|int $num 递减值
	 * @return int 变化的行数
	 */
	public function decrement( float|int $num = 1 ):int {
		return $this->getDataUnit()->goDataset()->decrement( $this->getName(), $num );
	}

	/**
	 * 自增或自减(马上执行)
	 * @param float|int $num 自增或自减值
	 * @return int 变化的行数
	 */
	public function incOrDec( float|int $num ):int {
		if( $num > 0 ){
			return $this->increment( $num );
		} else if( $num < 0 ){
			return $this->decrement( abs( $num ) );
		} else{
			return 0;
		}
	}

	/**
	 * 获取数据
	 * @param mixed $defaultValue 默认值
	 * @return mixed
	 */
	public function get( mixed $defaultValue = null ):mixed {
		return $this->getDataUnit()->goDataset()->get( $this->getName(), $defaultValue );
	}

	/**
	 * 获取设置的数据
	 * @param mixed $defaultValue 默认值
	 * @return mixed
	 */
	public function getSetData( mixed $defaultValue = null ):mixed {
		return $this->getDataUnit()->goDataset()->getSetData( $this->getName(), $defaultValue );
	}

	/**
	 * 获取设置的数据(从重置数据中获取)
	 * @return mixed
	 */
	public function getSetDataAsResetOrFail():mixed {
		return $this->getDataUnit()->goDataset()->getSetDataAsResetOrFail( $this->getName() );
	}

	/**
	 * 获取设置的数据(原始)
	 * @param mixed $defaultValue 默认值
	 * @return mixed
	 */
	public function getSetOriginalData( mixed $defaultValue = null ):mixed {
		if( $this->isset() ){
			return $this->get();
			// return $this->_data;
		}
		//
		return $defaultValue;
	}

	/**
	 * 获取模型更新数据(原始)
	 * @param mixed $defaultValue 默认值
	 * @return array|null
	 * @throws
	 */
	public function getModelUpdateData( mixed $defaultValue = null ):?array {
		if( $this->isset() ){
			$data = $this->get();
			if( ! is_object( $data ) ){
				return [
					$this->getName() => $data,
				];
			}
			//
			if( $data instanceof nameDataOperate\JsonOfArray ){
				return $data->getModelUpdateData();
			} else{
				throw com\Lib\Err\Exception::makeOfNew( '未知类型', com\Lib\Err\Code::$sysAssertError );
			}
		}
		//
		return [
			$this->getName() => $this->getDefaultValue() ?? $defaultValue
		];
	}

	/**
	 * 获取设置的数据(不存在则抛出异常)
	 * @return mixed
	 */
	public function getSetDataOrFail():mixed {
		return $this->getDataUnit()->goDataset()->getSetDataOrFail( $this->getName() );
	}

	/**
	 * 获取数据(优化获取SetData，不存在则获取数据库)
	 * @param mixed $defaultValue 默认值
	 * @return mixed
	 * @throws
	 */
	public function getLayerData( mixed $defaultValue = null ):mixed {
		return $this->getDataUnit()->goDataset()->getLayerData( $this->getName(), $defaultValue );
	}

	/**
	 * 获取数据(为null时抛出异常)
	 * @return mixed
	 * @throws
	 */
	public function getOrFail():mixed {
		return $this->getDataUnit()->goDataset()->getOrFail( $this->getName() );
	}

	/**
	 * 获取数据(从缓存中获取)
	 * @param mixed $default 默认数据
	 * @param bool $isForce 是否强制刷新数据访问。[false][默认]
	 * @return mixed
	 */
	public function getOfCache( mixed $default = null, bool $isForce = false ):mixed {
		return $this->getDataUnit()->goDataset()->getOfCache( $this->getName(), $default, $isForce );
	}

	/**
	 * 获取数据(从缓存中获取)
	 * @param mixed $default 默认数据
	 * @param bool $isForce 是否强制刷新数据访问。[false][默认]
	 * @return mixed
	 * @deprecated 与getOfCache功能一致，建议使用getOfCache
	 */
	public function getOfCaches( mixed $default = null, bool $isForce = false ):mixed {
		// return $this->getDataUnit()->goDataS()->getOfCache( $this->getName(), $default, $isForce );
		return $this->getDataUnit()->goDataset()->getOfCaches( $this->getName(), $default, $isForce );
	}

	/**
	 * 读取默认值
	 * @return mixed|null
	 */
	public function getDefaultValue():mixed {
		return $this->getDataUnit()->goDataset()->getDefaultValue( $this->getName() );
	}

	/**
	 * 获取数据(从缓存中获取)(为空时抛出异常)
	 * @param bool $isForce 是否强制刷新数据访问。[false][默认]
	 * @return mixed
	 * @throws
	 */
	public function getOfCacheOrFail( bool $isForce = false ):mixed {
		return $this->getDataUnit()->goDataset()->getOfCacheOrEmptyFail( $this->getName(), $isForce );
	}

	/**
	 * 获取数据(从缓存组中获取)(为空时抛出异常)
	 * @param bool $isForce 是否强制刷新数据访问。[false][默认]
	 * @return mixed|null [null]数据不存在
	 * @throws
	 * @deprecated 与getOfCacheOrFail功能一致，建议使用getOfCacheOrFail
	 */
	public function getOfCachesOrFail( bool $isForce = false ):mixed {
		return $this->getDataUnit()->goDataset()->getOfCachesOrEmptyFail( $this->getName(), $isForce );
	}

	/**
	 * 获取一列数据
	 * @return com\Lib\Utils\Helper\Array_
	 */
	public function pluck():com\Lib\Utils\Helper\Array_ {
		return $this->getDataUnit()->goDataset()->pluck( $this->getFieldAlias() );
	}

	/**
	 * 获取一列数据并合并为一个有序ids数组
	 * @return com\Lib\Utils\Helper\Array_
	 */
	public function pluckOfContinuousIds():com\Lib\Utils\Helper\Array_ {
		return $this->getDataUnit()->goDataset()->pluckOfContinuousIds( $this->getName() );
	}

	/**
	 * 检查指定对是否存在GoDirectData
	 * @param $classObj
	 * @return bool
	 */
	/*
	private function isExists_GoDirectData( $classObj ):bool {
		return method_exists( $classObj, 'goDirectData' );
	}
	*/

	/**
	 * 是否已上锁
	 * @return bool
	 */
	public function isLock():bool {
		return $this->getDataUnit()->goDataset()->isLock( $this->getName() );
	}

	/**
	 * 上锁
	 * @return $this
	 */
	public function lock():self {
		$this->getDataUnit()->goDataset()->lock( $this->getName() );
		return $this;
	}

	/**
	 * 解锁
	 * @return $this
	 */
	public function unlock():self {
		$this->getDataUnit()->goDataset()->unlock( $this->getName() );
		return $this;
	}

	/**
	 * 是否已设置
	 * @return bool
	 */
	public function isset():bool {
		return $this->getDataUnit()->goDataset()->isset( $this->getName() );
	}

	/**
	 * 设置数据
	 * @param mixed $data 数据
	 * @return $this
	 */
	public function set( $data ):self {
		$this->getDataUnit()->goDataset()->set( $this->getName(), $data );
		return $this;
	}

	/**
	 * 设置默认值
	 * @param mixed|\Closure $data 数据(支持传入数据闭关)
	 * @return $this
	 */
	public function setDefaultValue( mixed $data ):self {
		$this->getDataUnit()->goDataset()->setDefaultValue( $this->getName(), $data );
		return $this;
	}

	/**
	 * 设置数据（完整覆盖）
	 * @param string $keyPath 为空时则写入首层
	 * @param mixed $data 数据
	 * @return $this
	 */
	public function setOfJsonArray( string $keyPath, mixed $data ):self {
		$this->getDataUnit()->goDataset()->setOfJsonArray( $this->getName(), $keyPath, $data );
		return $this;
	}

	/**
	 * 设置数据(数组追加)
	 * @param string $keyPath 为空时则写入首层
	 * @param mixed $data 数据
	 * @return $this
	 */
	public function setOfJsonArrayAppend( string $keyPath, mixed $data ):self {
		$this->getDataUnit()->goDataset()->setOfJsonArrayAppend( $this->getName(), $keyPath, $data );
		return $this;
	}

	/**
	 * 设置数据
	 * @param string $keyPath 为空时则写入首层
	 * @param mixed $data 数据
	 * @return $this
	 */
	public function setOfStringArray( string $keyPath, mixed $data ):self {
		$this->getDataUnit()->goDataset()->setOfStringArray( $this->getName(), $keyPath, $data );
		return $this;
	}

	/**
	 * 设置数据(数组追加)
	 * @param string $keyPath 为空时则写入首层
	 * @param mixed $data 数据
	 * @return $this
	 */
	public function setOfStringArrayAppend( string $keyPath, $data ):self {
		$this->getDataUnit()->goDataset()->setOfStringArrayAppend( $this->getName(), $keyPath, $data );
		return $this;
	}

	/**
	 * 设置数据
	 * @param array $ids 数据
	 * @return $this
	 */
	public function setOfContinuousIds( array $ids ):self {
		$this->getDataUnit()->goDataset()->setOfContinuousIds( $this->getName(), $ids );
		return $this;
	}

	/**
	 * 设置数据(多条数据)
	 * @param array $manyString 数据
	 * @return $this
	 */
	public function setOfManyString( array $manyString ):self {
		$this->getDataUnit()->goDataset()->setOfManyString( $this->getName(), $manyString );
		return $this;
	}

	/**
	 * 设置数据
	 * @param mixed $data 数据
	 * @return $this|null [null]设置已存在，设置失败
	 */
	public function setNx( $data ):?self {
		if( $this->getDataUnit()->goDataset()->setNx( $this->getName(), $data ) === null ){
			return null;
		}
		return $this;
	}

	/**
	 * 获取field（包含前缀）
	 * @return string
	 */
	public function getFieldAlias():string {
		return $this->getDataUnit()->goDataset()->getFieldAlias( $this->getName() );
	}

	/**
	 * 加入到field
	 * @return $this
	 */
	public function addField():self {
		$this->getDataUnit()->goDataset()->addField( $this->getName() );
		//
		return $this;
	}

	/**
	 * 加入到field
	 * @param string $as 别名
	 * @return $this
	 */
	public function addFieldAs( string $as = null ):self {
		$this->getDataUnit()->goDataset()->addFieldAs( $this->getName(), $as );
		//
		return $this;
	}

	/**
	 * 判断数据是否存在
	 * @return bool [false]不存在 [true]存在
	 */
	public function isExist():bool {
		return $this->getDataUnit()->goDataset()->isExist( $this->getName() );
	}

	/**
	 * 判断数据是否存在，不存在则抛出异常
	 * @return bool
	 * @throws
	 */
	public function isExistOrFail():bool {
		return $this->getDataUnit()->goDataset()->isExistOrFail( $this->getName() );
	}

	/**
	 * 判断数据是否存在，存在则返回主键id
	 * @return int|null [null]不存在 [>0]存在，并返回主键id
	 * @throws
	 */
	public function isExistToID():?int {
		return $this->getDataUnit()->goDataset()->isExistToID( $this->getName() );
	}

	/**
	 * 判断数据是否存在，存在则返回主键id，不存在则抛出异常
	 * @return int [>0]存在，并返回主键id
	 * @throws
	 */
	public function isExistToIDOrFail():int {
		return $this->getDataUnit()->goDataset()->isExistToIDOrFail( $this->getName() );
	}

	/**
	 * 设置where条件
	 * @param mixed ...$args
	 * @return $this
	 */
	public function where( ...$args ):self {
		$this->getDataUnit()->goDataset()->where( $this->getName(), ...$args );
		//
		return $this;
	}

	/**
	 * 设置or where条件
	 * @param mixed ...$args
	 * @return $this
	 */
	public function orWhere( ...$args ):self {
		$this->getDataUnit()->goDataset()->orWhere( $this->getName(), ...$args );
		//
		return $this;
	}

	/**
	 * 设置where条件
	 * @param mixed ...$args
	 * @return $this
	 */
	public function whereOfJson( ...$args ):self {
		$this->getDataUnit()->goDataset()->whereOfJson( $this->getName(), ...$args );
		//
		return $this;
	}

	/**
	 * 设置where条件
	 * @param mixed ...$args
	 * @return $this
	 */
	public function whereJsonContains( ...$args ):self {
		$this->getDataUnit()->goDataset()->whereJsonContains( $this->getName(), ...$args );
		//
		return $this;
	}

	/**
	 * 设置where = 条件
	 * @param mixed $value
	 * @return $this
	 */
	public function whereEq( mixed $value ):self {
		$this->getDataUnit()->goDataset()->whereEq( $this->getName(), $value );
		//
		return $this;
	}

	/**
	 * 设置where != 条件
	 * @param mixed $value
	 * @return $this
	 */
	public function whereNotEq( mixed $value ):self {
		$this->getDataUnit()->goDataset()->whereNotEq( $this->getName(), $value );
		//
		return $this;
	}

	/**
	 * 设置where LIKE 条件
	 * @param mixed $value
	 * @return $this
	 */
	public function whereLike( $value ):self {
		$this->getDataUnit()->goDataset()->whereLike( $this->getName(), $value );
		//
		return $this;
	}

	/**
	 * 设置where LIKE 条件(ids条件)
	 * @param int $value ids
	 * @return $this
	 */
	public function whereLikeOfContinuousId( int $value ):self {
		$this->getDataUnit()->goDataset()->whereLikeOfContinuousId( $this->getName(), $value );
		//
		return $this;
	}

	/**
	 * 设置 or where LIKE 条件(ids条件)
	 * @param int $value ids
	 * @return $this
	 */
	public function orWhereLikeOfContinuousId( int $value ):self {
		$this->getDataUnit()->goDataset()->orWhereLikeOfContinuousId( $this->getName(), $value );
		//
		return $this;
	}

	/**
	 * 设置where LIKE 条件（连续的ids）
	 * @param array $value 连续的ids。如传入[ 2, 5 ]，则like条件为：'%,2,%,5,%'
	 * @return $this
	 */
	public function whereLikeOfContinuousIds( array $value ):self {
		$this->getDataUnit()->goDataset()->whereLikeOfContinuousIds( $this->getName(), $value );
		//
		return $this;
	}

	/**
	 * 设置where in 条件
	 * @param array|\Closure $inData
	 * @return $this
	 */
	public function whereIn( $inData ):self {
		/*		if( is_array( $inData ) && empty( $inData ) ){
					throw com\Lib\Err\Exception::makeOfNew( com\Lib\Err\Exception\Msg::$notAllowEmptyArray, com\Lib\Err\Code::$sysFunParamError );
				}*/
		//
		$this->getDataUnit()->goDataset()->whereIn( $this->getName(), $inData );
		//
		return $this;
	}

	/**
	 * 设置where in 条件(闭包)
	 * @param \Closure $fn ( \Hyperf\Database\Query\Builder $query )
	 * @return $this
	 */
	public function whereInFn( \Closure $fn ):self {
		$this->getDataUnit()->goDataset()->whereIn( $this->getName(), $fn );
		//
		return $this;
	}

	/**
	 * 设置where in 条件(执行闭包)
	 * @param \Closure $fn 格式：$fn():array{}，需返回一个数组
	 * @return $this
	 */
	public function whereInOfClosure( \Closure $fn ):self {
		$this->whereIn( $fn() );
		//
		return $this;
	}

	/**
	 * 设置where not in 条件
	 * @param array|\Closure $inData
	 * @return $this
	 */
	public function whereNotIn( $inData ):self {
		//
		$this->getDataUnit()->goDataset()->whereNotIn( $this->getName(), $inData );
		//
		return $this;
	}

	/**
	 * Add an "order by" clause to the query.
	 * @param string $direction
	 * @return $this
	 */
	public function orderBy( string $direction = 'asc' ):self {
		$this->getDataUnit()->goDataset()->orderBy( $this->getName(), $direction );
		//
		return $this;
	}

	/**
	 * Add a "group by" clause to the query.
	 * @return $this
	 */
	public function groupBy():self {
		$this->getDataUnit()->goDataset()->groupBy( $this->getName() );
		//
		return $this;
	}

	/**
	 * Add a descending "order by" clause to the query.
	 * @return $this
	 */
	public function orderByDesc():self {
		$this->orderBy( 'desc' );
		//
		return $this;
	}

	/**
	 * 保存自身(保存成功后销毁自身)
	 * @param bool $resetSelf 保存后是否销毁自身 [false]默认
	 * @return bool [true][必返]
	 */
	public function save( bool $resetSelf = false ):bool {
		return $this->getDataUnit()->goDataset()->save( $this->getName(), $resetSelf );
	}

	/**
	 * 重置自身
	 * @return $this
	 */
	public function resetSelf():self {
		$this->getDataUnit()->goDataset()->reset( $this->getName() );
		//
		return $this;
	}

}